/*
    This is a set of libraries to assist in OpenGl and Other Applications
    Copyright (C) 2008  The Modular Engine Team

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#define REGISTRYMODULE
#include "RegistryModule.h"

namespace ModularEngine
{


	int RegistryModule::initialize()
	{	
		// The Program is loaded, don't save this to a file
		setValue( "program_loaded", 1 );
		getKey( "program_loaded" ).mbSaveable = false;

		// Add RegistrySpecific commands to the console
		ADDCOMMAND( cSAVEREGISTRY );
		ADDCOMMAND( cLOADREGISTRY );
		ADDCOMMAND( cSET );

		// If the defaultRegistryFile is defined load her up.
		if( doesExist( "defaultRegistryFile" ) )
		{
			// load default registry file into memory
			loadRegistry( getKey( "defaultRegistryFile" )() );
		}

		return 1;
	}

	
	int RegistryModule::run()
	{
		// We don't do anything on loops
		return 1;
	}


	bool RegistryModule::doesExist( const char *keyName )
	{
		// If the key with this name is in the list then it exists
		for( list<RegistryKey>::iterator i = mKeys.begin(); i != mKeys.end(); i++ )
		{
			if( !strcmp( i->mKeyName, keyName ) )
			{
				return true;
			}
		}
		return false;
	}

	void RegistryModule::setValue( const char *keyName, void *pValue, int size )
	{
		// Find the key and set the value to the value we want.
		
		for( list<RegistryKey>::iterator i = mKeys.begin(); i != mKeys.end(); i++ )
		{
			if( !strcmp( i->mKeyName, keyName ) )
			{
				i->mKeyValue = (char *)pValue;
				return;
			}
		}

		// If the key doesn't exist, make it exist.
		RegistryKey tKey;
		tKey.setName( keyName );
		tKey.setOther( pValue, size );
		mKeys.push_back( tKey );
	}

	void RegistryModule::setValue(const char *keyName, double nValue)
	{
		// Set the value of the key to a double.  Same dealio as above
		for( list<RegistryKey>::iterator i = mKeys.begin(); i != mKeys.end(); i++ )
		{
			if( !strcmp( i->mKeyName, keyName ) )
			{
				*i = nValue;
				return;
			}
		}

		RegistryKey tKey;
		tKey.setName( keyName );
		tKey = nValue;
		mKeys.push_back( tKey );
	}

	void RegistryModule::setValue(const char *keyName, const char *pValue)
	{
		// Same dealio with strings
		for( list<RegistryKey>::iterator i = mKeys.begin(); i != mKeys.end(); i++ )
		{
			if( !strcmp( i->mKeyName, keyName ) )
			{
				*i = pValue;
				return;
			}
		}

		RegistryKey tKey;

		tKey.setName( keyName );
		tKey = pValue;
		mKeys.push_back( tKey );

	}

	RegistryKey &RegistryModule::getKey( const char *keyName )
	{
		// Return the reference to a key with the name keyName in the list
		for( list<RegistryKey>::iterator i = mKeys.begin(); i != mKeys.end(); i++ )
		{
			if( !strcmp( i->mKeyName, keyName ) )
				return (*i);
		}

		// Return an empty RegistryKey
		RegistryKey *k = 0;
		return *k;
	}

	int RegistryModule::loadRegistry( const char *path )
	{
		// Load the registry from a file
		// Should probably provide version checking in a later version.
		ifstream regFile( path );
		if( !!regFile )
		{
			int keyCount = 0;
			// Load the number of keys
			regFile.read( (char *)&keyCount, sizeof(keyCount) );
			for( int i = 0; i < keyCount; i++ )
			{
				RegistryKey tKey;
				int strLen = 0;
				// Load the size of the keyName
				regFile.read( (char *)&strLen, sizeof( strLen ) );
				tKey.mKeyName = new char[strLen];
				// The KeyName
				regFile.read( tKey.mKeyName, strLen );
				// Size of the value
				regFile.read( (char *)&tKey.mValSize, sizeof( tKey.mValSize ) );
				tKey.mKeyValue = new char[tKey.mValSize];
				// The Value
				regFile.read( tKey.mKeyValue, tKey.mValSize );
				// Put it in the registry
				setValue( tKey.mKeyName, tKey.mKeyValue, tKey.mValSize );
			}

			// Close the file
			regFile.close();
		} else {
			console( "Could Not Open File" );
			return 0;
		}
		return 1;
	}

	int RegistryModule::saveRegistry( const char *path )
	{
		// Save the registry to a file

		// Count the number of keys that are savable and exist
		int keyCount = 0;
		for( list<RegistryKey>::iterator i = mKeys.begin(); i != mKeys.end(); i++ )
		{
			if( i->mbSaveable && i->mKeyName && i->mKeyValue )
				keyCount++;
		}

		// Open the file
		ofstream regFile( path );
		if( !!regFile )
		{
			// Write the Number of keys
			regFile.write( (char *)&keyCount, sizeof( keyCount ) );
			for( list<RegistryKey>::iterator i = mKeys.begin(); i != mKeys.end(); i++ )
			{
				if( i->mbSaveable && i->mKeyName && i->mKeyValue )
				{						
					int strLen = strlen(i->mKeyName)+1;
					// write the length of Key Name
					regFile.write( (char *)&(strLen), sizeof(strLen) );
					// The KeyName
					regFile.write( i->mKeyName, strLen );
					// Write the length of the Value
					regFile.write( (char *)&i->mValSize, sizeof(i->mValSize) );
					// The Value
					regFile.write( i->mKeyValue, i->mValSize );
				}
			}
			// Close the file
			regFile.close();
		} else {
			console( "Could not write to file" );
			return 0;
		}

		return 1;
	}

	void cSAVEREGISTRY::init()
	{
		// Save Registry Path
		NEWARG( C_STRING );
	}

	void cSAVEREGISTRY::operator ()()
	{
		// Save the Registry
		RegistryModule::getSingleton().saveRegistry( (char *)mArgs[0].msArg.c_str() );
	}

	void cLOADREGISTRY::init()
	{
		// Load Registry Path
		NEWARG( C_STRING );
	}

	void cLOADREGISTRY::operator ()()
	{
		// Load the Registry
		if( !RegistryModule::getSingleton().loadRegistry( (char *)mArgs[0].msArg.c_str() ) )
		{
			console( "Could not load the registry!" );
		}
	}

	void cSET::init()
	{
		// The key name
		NEWARG( C_STRING );
		// The Value
		NEWARG( C_STRING );
	}

	void cSET::operator () ()
	{
		// Set the Key/Values
		RegistryModule::getSingleton().setValue( mArgs[0].msArg.c_str(), mArgs[1].msArg.c_str() );
	}
}